/* 
 * File:   Ray.cpp
 * Author: brady
 * 
 * Created on June 13, 2011, 7:01 PM
 */

#include <stack>

#include <core/Ray.h>

Ray::Ray() {
    this->recursionLimit = 0;
}

Ray::Ray(const Vector3D& origin, const Vector3D& direction, int recursionLimit){
    this->origin = origin;
    this->direction = direction;
    this->recursionLimit = recursionLimit;;
}

Ray::Ray(const Vector3D& origin, const Vector3D& direction){
    this->origin = origin;
    this->direction = direction;
    this->recursionLimit = 0;
}

Ray::~Ray() {
}

Vector3D Ray::follow(double tVal) const {
    Vector3D point = origin + (direction * tVal);
    return point;
}

Ray Ray::reflect(const Vector3D& normal, const Vector3D& hitPoint) const{
    //copy this ray
    Ray reflectedRay(*this);
    //reflect from point of intersection
    reflectedRay.origin = hitPoint;
    //calculate the new direction
    double c = -direction.dot(normal);
    reflectedRay.direction = direction + (normal*(2*c));
    reflectedRay.direction.normalize();
    //decrement the recursion limit counter
    reflectedRay.recursionLimit--;
    
    return reflectedRay;
}

Ray Ray::refract(const Vector3D& normal, const Vector3D& hitPoint, double newRefractiveIndex) const {
    //copy this ray as a starting point
    Ray refractedRay(*this);
    //refract from point of intersection
    refractedRay.origin = hitPoint;
    //calculate the new direction
    double n = 1.0/newRefractiveIndex;
    //if leaving the shape, flip the normal and the IoR's
    Vector3D adjustedNormal(normal);
    if(normal.dot(direction) > 0){
        n = 1.0/n;
        adjustedNormal *= -1.0;
    }
    double c1 = adjustedNormal.dot(direction) * -1.0;
    double c2 = 1.0 - ((1.0 - (c1 * c1))*(n*n));
    if(c2 < 0.0) //c2 is never < 0
    {
        //TIR. Return the reflected ray 
        return reflect(hitPoint, adjustedNormal);
    }
    refractedRay.direction = (direction * n) + adjustedNormal * ((n*c1) - sqrt(c2));
    refractedRay.direction.normalize();
    //decrement the recursion limit counter
    refractedRay.recursionLimit--;

    return refractedRay;
}

